package net.wangds.dymodel.query;

import net.wangds.dymodel.ddl.DyModelDdlComp;
import net.wangds.dymodel.meta.entity.DyModelPropDefEntity;
import net.wangds.dymodel.utls.DynamicModelUtils;
import net.wangds.log.helper.LogHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static net.wangds.dymodel.query.ConditionVerbEnum.*;

/**
 * 条件解析器.
 * <p></p>
 *
 * @author 王东石 2021/2/16 2:43.
 */
@Component
@SuppressWarnings("unused")
public class ConditionParse {

    public static final String PREFIX_DY_COL_ID = "dyCol:";

    @Autowired
    private DyModelDdlComp mmCmpDyMdl;

    public String toWhere(Condition c){
        String where = " 1=1 ";
        if (c==null) {
            return where;
        }
        List<Object> args = c.getArguments();
        if(CollectionUtils.isEmpty(args)){
            return where;
        }
        int argsSize = args.size(); //参数长度
        ConditionVerbEnum verb = c.getVerb();
        switch (c.getVerb()){
            case NOT:
                where = " NOT " + toWhere((Condition)(args.get(0)));
                break;
            case EXISTS:
                where = " exists (" + toWhere((Condition)(args.get(0)))+")";
                break;
            case IN:

                break;
            case AND:
                StringBuilder sbAnd = new StringBuilder("(");
                for(int i=0;i<argsSize;i++){
                    if(i>0){
                        sbAnd.append(" AND ");
                    }
                    String str = toWhere((Condition)args.get(i));
                    if(str.startsWith("(")){
                        sbAnd.append(str);
                    }else {
                        sbAnd.append("(");
                        sbAnd.append(str);
                        sbAnd.append(")");
                    }
                }
                sbAnd.append(")");
                where = sbAnd.toString();
                break;
            case OR:
                StringBuilder sbOr = new StringBuilder("(");
                for(int i=0;i<argsSize;i++){
                    if(i>0){
                        sbOr.append(" OR ");
                    }
                    String str = toWhere((Condition)args.get(i));
                    if(str.startsWith("(")){
                        sbOr.append(str);
                    }else {
                        sbOr.append("(");
                        sbOr.append(str);
                        sbOr.append(")");
                    }
                }
                sbOr.append(")");
                where = sbOr.toString();
                break;
            case MATCH:
                //MATCH(字段名) AGAINST('条件字符串1*')
                // MATCH('material_name') AGAINST('塑料*' IN BOOLEAN MODE)
                // and MATCH('material_name') AGAINST('20*' IN BOOLEAN MODE)

                //StringBuilder searchValue = new StringBuilder(String.valueOf(args.get(1)));
                //for(int i=2;i<argsSize;i++){
                //    searchValue.append(" ").append(args.get(i));
                //}
                //Object a0 = args.get(0);
                //where = String.format(" MATCH(%s) AGAINST('%s' IN BOOLEAN MODE) ",
                //        a0 instanceof DyModelPropDefEntity?buildColumnName((DyModelPropDefEntity) a0):buildColumnName(String.valueOf(a0)),searchValue.toString());
                //break;
            case EQUALS:
            case NOT_EQUALS:
            case GT:
            case GE:
            case LT:
            case LE:
            case REGEXP:
                //二元运算符的多条件展开
                if(argsSize==2){
                    Object oLeft = args.get(0);
                    Object oRight = args.get(1);
                    StringBuilder sb2 = new StringBuilder(" ");

                    if(oLeft instanceof String&& StringUtils.startsWith((String)oLeft, PREFIX_DY_COL_ID)){
                        sb2.append(buildColumnName((String)oLeft));
                    }else if (oLeft instanceof DyModelPropDefEntity){
                        sb2.append(buildColumnName((DyModelPropDefEntity) oLeft));
                    }else{
                        sb2.append(toValue(oLeft));
                    }

                    switch (verb){
                        case EQUALS:
                            sb2.append(" = ");
                            break;
                        case NOT_EQUALS:
                            sb2.append(" != ");
                            break;
                        case GT:
                            sb2.append(" > ");
                            break;
                        case GE:
                            sb2.append(" >= ");
                            break;
                        case LT:
                            sb2.append(" < ");
                            break;
                        case LE:
                            sb2.append(" <= ");
                            break;
                        case REGEXP:
                        case MATCH:
                            sb2.append(" regexp ");
                            break;
                    }
                    if(oRight instanceof String&& StringUtils.startsWith((String)oRight, PREFIX_DY_COL_ID)){
                        sb2.append(buildColumnName((String)oRight));
                    }else{
                        sb2.append(toValue(oRight));
                    }

                    sb2.append(" ");

                    where = sb2.toString();

                }else{
                    if(verb==REGEXP||verb==MATCH){
                        where = toWhere(toGroup(OR, verb, args));
                    }else {
                        where = toWhere(toGroup(AND, verb, args));
                    }
                }
                break;
        }
        return where;
    }

    private String toValue(Object arg) {
        if(arg instanceof String){
            return "'"+arg+"'";
        }
        return String.valueOf(arg);
    }

    private String buildColumnName(String defId) {
        String colId = StringUtils.removeStart(defId, PREFIX_DY_COL_ID);

        Optional<DyModelPropDefEntity> opCol = mmCmpDyMdl.findColumn(colId);
        if(opCol.isPresent()){
            DyModelPropDefEntity col = opCol.get();
            return DynamicModelUtils.toColumnName(col);
        }else{
            throw new RuntimeException("找不到动态模型列定义:"+colId);
        }
    }

    private String buildColumnName(DyModelPropDefEntity col) {
        return DynamicModelUtils.toColumnName(col);
    }

    private Condition toGroup(ConditionVerbEnum verbOut,ConditionVerbEnum verb, List<Object> args) {
        Condition res = new Condition();
        res.setVerb(verbOut);

        Object left = args.get(0);
        int len = args.size();
        List<Object> newArgs = new ArrayList<>();
        for(int i=1;i<len;i++){
            Condition c = new Condition();
            Object right = args.get(i);
            c.setVerb(verb);
            List<Object> inArgs = new ArrayList<>();
            inArgs.add(left);
            inArgs.add(right);
            c.setArguments(inArgs);
            newArgs.add(c);
        }
        res.setArguments(newArgs);
        return res;
    }


}
